import logging

from django import http
from django.core.paginator import Paginator
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View

from apps.contents.utils import get_categories
from apps.goods.models import SKU, GoodsCategory, GoodsVisitCount
from apps.goods.utils import get_breadcrumb
from utils.response_code import RETCODE

"""
前端要收集分类ID，
后端根据需要查询数据

1、根据分类ID，把所有数据都查询出来
2、如果有排序字段，再排序
3、如果有分页字段，再分页

GET     /list/(?P<category_id>\d+)/(?P<page_num>\d+)/?sort=排序方式
"""
logger = logging.getLogger('django')


class ListView(View):
    def get(self, request, category_id, page_num):
        # 一、面包屑
        # ① 获取当前分类
        try:
            category = GoodsCategory.objects.get(id=category_id)
        except Exception as e:
            logger.error(e)
            return render(request, 'list.html', context={'errmsg': '没有此分类'})
        # ② 获取它的上级/下级
        breadcrumb = get_breadcrumb(category)

        # 二、列表数据

        # 1、如果有排序字段，再排序
        sort = request.GET.get('sort')
        # sort=hot      人气，根据销量排序
        # sort=price    价格，根据价格排序
        # sort=default  默认，根据create_time排序
        if sort == 'hot':
            order_filed = 'sales'
        elif sort == 'price':
            order_filed = 'price'
        else:
            order_filed = 'create_time'
            sort = 'default'
        # 2、根据分类ID，把所有数据都查询出来
        skus = SKU.objects.filter(category_id=category_id, is_launched=True).order_by(order_filed)

        # 防止用户随便输入数值
        try:
            page_num = int(page_num)
        except Exception as e:
            page_num = 0
        # 3、如果有分页字段，再分页
        try:
            # 3.1、创建分页实例
            paginator = Paginator(skus, per_page=5)
            # 3.2、获取分页数据
            page_skus = paginator.page(page_num)
            # 总页数
            total_page = paginator.num_pages
        except Exception as e:
            pass

        context = {
            'category': category,  # 频道分类
            'breadcrumb': breadcrumb,  # 面包屑导航
            'sort': sort,  # 排序字段
            'page_skus': page_skus,  # 分页后数据
            'total_page': total_page,  # 总页数
            'page_num': page_num,  # 当前页码
        }

        return render(request, 'list.html', context=context)


# 热门数据
class HotView(View):
    def get(self, request, category_id):
        # 1、获取分类ID
        # 2、查询是否有当前分类
        try:
            category = GoodsCategory.objects.get(id=category_id)
        except Exception as e:
            return http.JsonResponse({'code': RETCODE.NODATAERR, 'errmsg': '暂无此类数据'})
        # 3、根据分类去查询指定的数据，并进行排序，排序之后获取n条
        skus = SKU.objects.filter(category=category, is_launched=True).order_by('-sales')[:2]
        # 4、ajax把对象列表转换为字典列表
        skus_list = []
        for sku in skus:
            skus_list.append({
                'id': sku.id,
                'default_image_url': sku.default_image.url,
                'name': sku.name,
                'price': sku.price
            })
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'hot_skus': skus_list})


# 详情页面
class DetailView(View):
    def get(self, request, sku_id):
        # 获取当前sku的信息
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return render(request, '404.html')

        # 查询商品频道分类
        categories = get_categories()
        # 查询面包屑导航
        breadcrumb = get_breadcrumb(sku.category)

        # 构建当前商品的规格键
        sku_specs = sku.specs.order_by('spec_id')
        sku_key = []
        for spec in sku_specs:
            sku_key.append(spec.option.id)
        # 获取当前商品的所有SKU
        skus = sku.spu.sku_set.all()
        # 构建不同规格参数（选项）的sku字典
        spec_sku_map = {}
        for s in skus:
            # 获取sku的规格参数
            s_specs = s.specs.order_by('spec_id')
            # 用于形成规格参数-sku字典的键
            key = []
            for spec in s_specs:
                key.append(spec.option.id)
            # 向规格参数-sku字典添加记录
            spec_sku_map[tuple(key)] = s.id
        # 获取当前商品的规格信息
        goods_specs = sku.spu.specs.order_by('id')
        # 若当前sku的规格信息不完整，则不再继续
        if len(sku_key) < len(goods_specs):
            return
        for index, spec in enumerate(goods_specs):
            # 复制当前sku的规格键
            key = sku_key[:]
            # 该规格的选项
            spec_options = spec.options.all()
            for option in spec_options:
                # 在规格参数sku字典中查找符合当前规格的sku
                key[index] = option.id
                option.sku_id = spec_sku_map.get(tuple(key))
            spec.spec_options = spec_options

        # 渲染页面
        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'sku': sku,
            'specs': goods_specs,
        }
        return render(request, 'detail.html', context)


"""
当用户在列表页/详情页的时候，要给后台发一个统计访问的请求
这个请求包含分类ID
后台接收到这个请求，就对它的个数+1

后台：根据ID查询分类
    将当天的统计个数+1
    

1、获取分类ID
2、根据ID查询分类，判断分类是否存在
3、以天为单位，如果当天没有统计数据，则应该新增统计数据
            如果当天有统计数据，则应该更新统计数据
4、返回相应


GET     detail/visit/(?P<category_id>\d+)/
"""


class VisitCategoryView(View):

    def get(self, request, category_id):
        # ① 获取分类id
        # ② 根据分类id查询分类,判断分类是否存在
        try:
            category = GoodsCategory.objects.get(id=category_id)
        except Exception as e:
            logger.error(e)
            return render(request, '404.html')

        # 我们需要查询 当天的,分类id的记录
        # yyyy-mm-dd
        # from datetime import datetime
        # now = datetime.now()
        # today_date = datetime.strptime(now,'%Y-%m%-%d')

        today = timezone.localdate()
        try:
            gvc = GoodsVisitCount.objects.get(date=today, category_id=category_id)
        except GoodsVisitCount.DoesNotExist:
            #      我们以天为单位,如果当天有统计数据,则应该更新统计数据
            GoodsVisitCount.objects.create(
                date=today,
                count=1,
                category_id=category_id
            )
        else:
            gvc.count += 1
            gvc.save()
            # ③ 我们以天为单位,如果当天没有统计数据,则应该新增统计数据

        # ④ 返回相应
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})
